﻿using Face8280WebSocketServer.DB.Log;
using Face8280WebSocketServer.Interface;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System.IO;
using System.Threading.Tasks;
using Newtonsoft.Json;
using System.Collections.Generic;
using System;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json.Serialization;

namespace Face8280WebSocketServer.Controllers.DeviceAPI
{
    public class FaceAPILogResourceFilter : IResourceFilter
    {
        private static Snowflake.Core.IdWorker RequestWorker;
        private static readonly Dictionary<string, string> PathNames;
        private static  HashSet<string> Headerfilter = new HashSet<string>();

        private static JsonSerializerSettings JsonSettings = new JsonSerializerSettings()
        {
            ContractResolver = new CamelCasePropertyNamesContractResolver(),
            DateFormatString = "yyyy-MM-dd HH:mm:ss",
            NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore

        };

        static FaceAPILogResourceFilter()
        {
            RequestWorker = new Snowflake.Core.IdWorker(1, 1);
            PathNames = new Dictionary<string, string>();
            PathNames.Add("note/insertNoteFace", "上传打卡记录");
            PathNames.Add("device/updateStateDevice", "设备心跳包");
            PathNames.Add("devicePass/selectPassInfo", "拉取人员");
            PathNames.Add("devicePass/setPassResult", "拉取人员反馈");
            PathNames.Add("devicePass/selectDeleteInfo", "删除人员");
            PathNames.Add("devicePass/setDeleteResult", "删除人员反馈");
            PathNames.Add("device/selectRestart", "远程操作");
            PathNames.Add("parameter/inertParameter", "上传参数");
            PathNames.Add("parameter/selectParameterInfo", "拉取参数");



            Headerfilter.Add("Cache-Control");
            Headerfilter.Add("Connection");
            Headerfilter.Add("Pragma");
            Headerfilter.Add("Accept");
            Headerfilter.Add("Accept-Language");
            Headerfilter.Add("User-Agent");

        }


        private readonly string APIPathStart = "/FaceAPI/";


        private IConnectIOLogService _logDB;
        private string APIName = string.Empty;
        private string IPAddr = string.Empty;
        private string URL = string.Empty;
        private string DeviceSN = string.Empty;
        private string RequestID = string.Empty;

        public FaceAPILogResourceFilter(IConnectIOLogService db)
        {
            _logDB = db;
        }

        public void OnResourceExecuted(ResourceExecutedContext context)
        {
            //处理执行其他中间件后的ResponseBody
            var Result = context.Result as IActionResult;
            var http = context.HttpContext;
            var ret = http.Request;


            ConnectIOLog ResponseLog = new ConnectIOLog()
            {
                HttpType = "Response",
                IPAddr = IPAddr,
                LogTime = System.DateTime.Now,
                URL = APIName + "  " + URL,
                Method = ret.Method,
                ContentLength = string.Empty,
                ContentType = "application/json; charset=utf-8",
                Body = string.Empty,
                DeviceSN = DeviceSN,
                RequestID = RequestID
            };

            //var obj = JsonConvert.SerializeObject(Result, JsonSettings);


            Dictionary<string, string> headers = new Dictionary<string, string>();

            //Headerfilter.Add("Host");
            foreach (var item in http.Response.Headers.Keys)
            {
                if (!Headerfilter.Contains(item))
                    headers.Add(item, ret.Headers[item].ToString());
            }

            Dictionary<string, object> body = new Dictionary<string, object>();
            body.Add("Headers", headers);
            body.Add("Body", Result);


            ResponseLog.Body = JsonConvert.SerializeObject(body, JsonSettings);
            ResponseLog.ContentLength = ResponseLog.Body.Length.ToString();

            _logDB.AddConnectLog(ResponseLog);
        }

        public void OnResourceExecuting(ResourceExecutingContext context)
        {
            var http = context.HttpContext;
            var ret = http.Request;
            URL = ret.Path;


            var sAPIPath = URL.Substring(APIPathStart.Length);
            if (PathNames.ContainsKey(sAPIPath))
            {
                APIName = PathNames[sAPIPath];
            }
            Dictionary<string, string> headers = new Dictionary<string, string>();

            //Headerfilter.Add("Host");
            foreach (var item in ret.Headers.Keys)
            {
                if (!Headerfilter.Contains(item))
                    headers.Add(item, ret.Headers[item].ToString());
            }


            ret.EnableBuffering();
            RequestID = RequestWorker.NextId().ToString();

            //X-Forwarded-For
            if (ret.Headers.ContainsKey("X-Forwarded-For"))
            {
                IPAddr = ret.Headers["X-Forwarded-For"].ToString();
            }
            else
                IPAddr = $"{http.Connection.RemoteIpAddress}:{http.Connection.RemotePort}";
            var sHost = string.Empty;
            if (ret.Headers.ContainsKey("Host"))
                sHost = ret.Headers["Host"].ToString();
            URL = $"{sHost}{URL}";
            ConnectIOLog RequestLog = new ConnectIOLog()
            {
                HttpType = "Request",
                IPAddr = IPAddr,
                LogTime = System.DateTime.Now,
                URL = $"{APIName} -- {URL}",
                Method = ret.Method,
                ContentLength = string.Empty,
                ContentType = string.Empty,
                Body = string.Empty,
                DeviceSN = DeviceSN,
                RequestID = RequestID
            };

            if (ret.ContentLength.HasValue)
            {
                RequestLog.ContentType = ret.ContentType;
                RequestLog.ContentLength = ret.ContentLength.Value.ToString();

                if (RequestLog.ContentType.StartsWith("multipart/form-data"))
                {
                    var sBuf = new System.Text.StringBuilder();

                    try
                    {
                        sBuf.Append("{");

                        foreach (var key in ret.Form.Keys)
                        {
                            string sValue = ret.Form[key];

                            sBuf.Append("\"").Append(key).Append("\":").Append(sValue).AppendLine(",");
                            try
                            {
                                //尝试读取
                                var dic = JsonConvert.DeserializeObject<Dictionary<string, object>>(sValue);
                                if (dic.ContainsKey("deviceId"))
                                {
                                    DeviceSN = dic["deviceId"].ToString();
                                    RequestLog.DeviceSN = DeviceSN;
                                }
                            }
                            catch (System.Exception)
                            {


                            }
                        }

                        foreach (var file in ret.Form.Files)
                        {
                            sBuf.Append("\"").Append(file.FileName).Append("\":").Append("{\"ContentType\":\"").Append(file.ContentType).Append("\",")
                                .Append("\"ContentDisposition\" :\"").Append(file.ContentDisposition.Replace("\"", "\\\"")).Append("\",")
                                .Append("\"Length\" :\"").Append(file.Length).Append("\",")
                                .Append("\"Name\" :\"").Append(file.Name).Append("\",")
                                .Append("\"FileName\" :\"").Append(file.FileName).Append("\"},")
                                ;

                        }
                        sBuf.Length -= 1;
                        sBuf.Append("}");

                        RequestLog.Body = sBuf.ToString();
                    }
                    catch (Exception ex)
                    {

                        sBuf.Append(ex.ToString());
                    }


                }
                else
                {
                    try
                    {
                        http.Request.Body.Position = 0;
                        using (var requestReader = new StreamReader(ret.Body, encoding: System.Text.Encoding.UTF8, leaveOpen: true))
                        {
                            var requestContent = requestReader.ReadToEndAsync().Result;
                            RequestLog.Body = requestContent;
                            try
                            {
                                //尝试读取
                                var dic = JsonConvert.DeserializeObject<Dictionary<string, object>>(requestContent);
                                if (dic.ContainsKey("deviceId"))
                                {
                                    DeviceSN = dic["deviceId"].ToString();
                                    RequestLog.DeviceSN = DeviceSN;
                                }
                            }
                            catch (System.Exception)
                            {


                            }
                        }
                    }
                    catch (Exception ex)
                    {

                        RequestLog.Body = $"{{\"err\":\"读取Body时发生错误！{ex.ToString()}\"}}";
                    }

                    http.Request.Body.Position = 0;
                }
            }

            if(!string.IsNullOrEmpty(RequestLog.Body))
            {
                System.Text.StringBuilder sBuf = new System.Text.StringBuilder();
                sBuf.Append("{\"Header\":").Append(headers.ToJson());
                sBuf.Append(",\"Body\":").Append(RequestLog.Body).Append("}");
                RequestLog.Body = sBuf.ToString();
            }
            _logDB.AddConnectLog(RequestLog);

        }
    }






}
